type O<T> = Record<keyof T | any, any>

type Method = 'get' | 'GET' | 'post' | 'POST'

interface AjaxRequest<T> {
    url: string
    method: Method
    params?: O<T>
    data?: O<T>
}

interface AjaxResponse<T = any> {
    data: T
    status: number
}

function Ajax<T, R>(options: AjaxRequest<T>): Promise<AjaxResponse<R>> {
    const { url, method = 'get', data = {}, params = {} } = options
    const xhr: XMLHttpRequest = new XMLHttpRequest()

    if (method === 'GET') {
        xhr.open(method.toUpperCase(), url, true)
    }

    if (method === 'POST') {
        xhr.open(method.toUpperCase(), url, true)
        xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
        xhr.send(JSON.stringify(data))
    }

    return new Promise((resolve, reject) => {
        xhr.onreadystatechange = () => {
            if (xhr.readyState !== 4 || xhr.status === 0) return
            try {
                const resData: AjaxResponse<R> = JSON.parse(xhr.response)
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(resData)
                }
            } catch (e) {
                reject(e)
            }
        }
    })
}

const get = <T extends O<T>>(url: string, params: T): Promise<AjaxResponse> => {
    return Ajax({ url: url, method: 'get', params: params })
}

const post = <T extends O<T>>(url: string, data: T): Promise<AjaxResponse> => {
    return Ajax({ url: url, method: 'get', data: data })
}

interface User {
    name: string
    age: number
}

const UserParams: User = {
    name: '王',
    age: 18
}

get('xxx', UserParams).then(res => {
    console.log(res.data)
})

const UserA = {}

get('xxx', UserA).then(res => {
    console.log(res.data)
})
